package com.jeecg.modules.service;

import com.alibaba.fastjson.JSONObject;
import lombok.SneakyThrows;
import okhttp3.OkHttpClient;
import org.jeecg.modules.jmreport.api.JmReportTokenServiceI;
import org.jose4j.jwe.JsonWebEncryption;
import org.jose4j.jws.AlgorithmIdentifiers;
import org.jose4j.jws.JsonWebSignature;
import org.jose4j.jwt.JwtClaims;
import org.jose4j.jwt.MalformedClaimException;
import org.jose4j.jwt.consumer.InvalidJwtException;
import org.jose4j.jwt.consumer.JwtConsumer;
import org.jose4j.jwt.consumer.JwtConsumerBuilder;
import org.jose4j.keys.HmacKey;
import org.jose4j.lang.JoseException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

@Component
//@Scope("prototype")
public class JimuReportTokenService implements JmReportTokenServiceI {

    @Value("${secret-key:}")
    private String secretKey;

    private HmacKey hmacKey = null;

    private final OkHttpClient client;

    public JimuReportTokenService() {
        this.client = new OkHttpClient();
    }

    private String generateJwt(String username) {
        try {
            // 创建声明集
            JwtClaims claims = new JwtClaims();
//            claims.setIssuer("https://example.com"); // 设置发行人
//            claims.setAudience("https://api.example.com"); // 设置受众
            claims.setExpirationTimeMinutesInTheFuture(10); // 设置过期时间
//            claims.setGeneratedJwtId(); // 自动生成jwt id
            claims.setIssuedAtToNow(); // 设置发行时间
//            claims.setNotBeforeMinutesInThePast(2); // 设置在此时间之前不可用
//            claims.setSubject("subject-id"); // 设置主题
            claims.setStringClaim("username", username); // 自定义字段
            claims.setStringListClaim("roles", "admin", "lowdeveloper", "dbadeveloper");
            claims.setStringListClaim("permissions", "drag:datasource:testConnection", "onl:drag:clear:recovery", "drag:analysis:sql", "drag:design:getTotalData");

            // 创建JsonWebSignature对象
            JsonWebSignature jws = new JsonWebSignature();

            // 设置载荷
            jws.setPayload(claims.toJson());

            // 设置签名算法
            jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.HMAC_SHA256);

            // 设置签名密钥
            jws.setKey(getHmacKey());

            // 签发JWT
            String jwt = jws.getCompactSerialization();
            return jwt;
        } catch (JoseException e) {
            throw new RuntimeException(e);
        }
    }

    private static String base64UrlDecode(String input) {
        try {
            // 1. 解码 Base64 字符串
            System.out.println("input");
            System.out.println(input);
            byte[] decodedBytes = Base64.getDecoder().decode(input);
            // 2. 返回解码后的字符串
            return new String(decodedBytes, StandardCharsets.UTF_8);
        } catch (IllegalArgumentException e) {
            // 捕获 Base64 解码异常
            throw new RuntimeException("Base64 URL Decode 出错，请检查输入字符串格式", e);
        }
    }

    private JwtClaims encryption(String jwt) throws JoseException, InvalidJwtException {
        // 分割JWT字符串
        String[] parts = jwt.split("\\.");
        if (parts.length < 3) {
            throw new JoseException("Invalid JWT format");
        }

        // 获取载荷部分并进行Base64解码
        String payloadBase64UrlEncoded = parts[1];
        String payloadJson = base64UrlDecode(payloadBase64UrlEncoded);
        System.out.println(payloadJson);
        // 将载荷部分解析为JwtClaims
        JwtClaims claims = JwtClaims.parse(payloadJson);
        System.out.println("claims");
        System.out.println(claims);
        return claims;
    }

    private HmacKey getHmacKey() {
        if (secretKey == null || secretKey.isEmpty()) {
            return null;
        }
        if (hmacKey == null) {
            hmacKey = new HmacKey(secretKey.getBytes());
        }
        return hmacKey;
    }

    @Override
    public String getToken(HttpServletRequest request) {
        String token = request.getParameter("token");
        if (token == null || token.isEmpty()) {
            token = request.getParameter("shareToken");
        }
        if (token == null || token.isEmpty()) {
            token = request.getHeader("Authorization");
            if (token == null || token.isEmpty()) {
                token = request.getHeader("X-Access-Token");

                if (token == null || token.isEmpty()) {
                    token = request.getHeader("");
                }
            }
        }

        if (token == null || token.isEmpty()) {
            HttpSession session = request.getSession(false);
            if (session != null) {
                Object o = session.getAttribute("SPRING_SECURITY_CONTEXT");
                if (o != null) {
                    SecurityContextImpl securityContext = (SecurityContextImpl) o;
                    token = generateJwt(securityContext.getAuthentication().getName());
                }
            }
        }

        return token;
    }

    @SneakyThrows
    @Override
    public String getUsername(String token) {
//        return JwtUtil.getUsername(token);
        JwtClaims jwtClaims = encryption(token);
        return jwtClaims.getStringClaimValue("schema_name") + jwtClaims.getStringClaimValue("username");
    }

    @SneakyThrows
    @Override
    public String[] getRoles(String token) {
        JwtClaims jwtClaims = encryption(token);
        String schemaName = jwtClaims.getStringClaimValue("schema_name");
        Long userId = jwtClaims.getClaimValue("user_id", Long.class);
        System.out.println(schemaName);
        System.out.println("user_id");
        if (schemaName == null || schemaName.isEmpty()) {
            if (userId == 1L) {
                return new String[]{"admin","lowdeveloper","dbadeveloper"};
            }
            return new String[]{};
        }
        if ("public".equals(schemaName)){
            if (userId == 1L) {
                System.out.println("public-ok");
                return new String[]{"admin","lowdeveloper","dbadeveloper"};
            }
            System.out.println("public-no");
        }
        return new String[]{};
    }

    @SneakyThrows
    @Override
    public Boolean verifyToken(String token) {
        // 创建 JWT Consumer
        JwtConsumer jwtConsumer = new JwtConsumerBuilder()
                .setRequireExpirationTime() // 需要存在过期时间
                .setAllowedClockSkewInSeconds(30) // 允许30秒的时间偏移
//                .setRequireSubject() // 需要存在主题
//                .setExpectedIssuer("issuer") // 如果有发行者要求
//                .setExpectedAudience("audience") // 如果有受众要求
                .setVerificationKey(getHmacKey()) // 设置用于验证签名的密钥
                .build();

        // 验证并解码 JWT
        try {
            JwtClaims jwtClaims = jwtConsumer.processToClaims(token);
        } catch (InvalidJwtException e) {
            return false;
        }

        return true;
    }

    private Map<String, Object> convertMap(JwtClaims jwtClaims) {
        Map<String, Object> map = new HashMap<>();

        Map<String, Object> claimsMap = jwtClaims.getClaimsMap();

        // 遍历所有声明
        for (Map.Entry<String, Object> entry : claimsMap.entrySet()) {
            String claimName = entry.getKey();
            Object claimValue = entry.getValue();

            if (checkDataType(claimValue)) {
                map.put(claimName, claimValue);
            }
        }
        return map;
    }

    private Boolean checkDataType(Object obj) {
        if (obj == null) {
            System.out.println("对象为null");
            return true;
        }

        Class<?> clazz = obj.getClass();

        /*if (clazz == int.class || clazz == long.class || clazz == double.class ||
                clazz == float.class || clazz == short.class || clazz == byte.class ||
                clazz == char.class || clazz == boolean.class) {
            return true;
        } else */
        if (clazz == Integer.class || clazz == Long.class || clazz == Double.class ||
                clazz == Float.class || clazz == Short.class || clazz == Byte.class ||
                clazz == Character.class || clazz == Boolean.class) {
            return true;
        } else if (clazz.isArray()){
            Class<?> componentType = clazz.getComponentType();

            // 检查数组元素类型是否为String或int
            if (componentType == String.class) {
                return true;
            } else if (componentType == int.class || componentType == Integer.class) {
                return false;
            }
        }
        return false;
    }


    @SneakyThrows
    @Override
    public Map<String, Object> getUserInfo(String token) {
        JwtClaims claims = encryption(token);

        return convertMap(claims);

    }


}

// JWT secret key 提供外部接入
// TODO: 获取更多参数 将所有可见参数都放进去
//  xss防护
// 一级变量解析
// 二级变量只解析数组,且类型只能是数字何字符串